package kr.ac.kookmin.cs.random;

import kr.ac.kookmin.cs.randomtest.RandomNumberSequenceGenerator;

public class MersenTwister extends RandomNumberSequenceGenerator {

	private long[] MT = new long[624];
	private int index = 0;
	
	@Override
	public void initialize(long seed){
		super.initialize(seed);
		index = 0;
		MT[0] = getSeed();
		
		for (int i = 1 ; i < 624 ; i++) { // loop over each other element
	         MT[i] = 0x00000000ffffffff & (1812433253L * (MT[i-1] ^ (MT[i-1] >>> 30)) + i); // 0x6c078965
	    }
		
	}

	@Override
	protected long getNextRandomNumber() {
		if(index == 0) {
	         generateNumbers();
	     }
	 
	     long y = MT[index];
	     y = y ^ (y >>> 11);
	     y = y ^ ((y << 7) & (2636928640L)); // 0x9d2c5680
	     y = y ^ ((y << 15) & (4022730752L)); // 0xefc60000
	     y = y & 0x00000000ffffffffL; //my code
	     //System.out.println("y>>32 1: " + (y>>32));
	     y = y ^ (y >>> 18);

	     index = (index + 1) % 624;
	     
	     //System.out.println("y>>32 2: " + (y>>32));
	     
	     return y;
	}

	private void generateNumbers() {
	     for (int i = 0 ; i < 624 ; i++) {
	         long y = (MT[i] & 0x80000000)                       // bit 31 (32nd bit) of MT[i]
	                        + (MT[(i+1) % 624] & 0x7fffffff);   // bits 0-30 (first 31 bits) of MT[...]
	         MT[i] = MT[(i + 397) % 624] ^ (y >>> 1);
	         if ((y % 2) != 0) { // y is odd
	             MT[i] = MT[i] ^ (2567483615L); // 0x9908b0df
	         }
	     }
	 }
	

	@Override
	protected long getRandomNumberWithSeed(long seed) {
		initialize(seed);
		return getNextRandomNumber();
		
	}
}
